# -*- coding: utf-8 -*-
#!/usr/bin/python
# This is probably useful to like 4 people. Some of the packet inection stuff is taken from rule2alert https://code.google.com/p/rule2alert/ which is GPLv2 so I guess this is well.
# This ultra alpha if everything isn't right it will fall on its face and probably cause you to run away from it screaming into the night

#TODO:
# 1. Optionally trim request line to start with uripath 
# 2. Better error checking... Well any error checking really.

import random
import os
import sys
import re
import zipfile
import tempfile
import shutil
from xml.dom.minidom import parse, parseString
from scapy.utils import PcapWriter
from scapy.all import *
import glob
from optparse import OptionParser

# parser = OptionParser()
# parser.add_option("-o", dest="output_pcap", type="string", help="path to output PCAP file")
# parser.add_option("--src", dest="srcip", type="string", help="src ip address to use if not specified we read it from the XML")
# parser.add_option("--dst", dest="dstip", type="string", help="dst ip address to use if not specified we read it from the XML")
# parser.add_option("--req_payload", dest="req_payload", type="string", help="")
# parser.add_option("--rsq_payload", dest="rsq_payload", type="string", help="")

class BUILD2PCAP():
    output_pcap = ""
    src = None
    dst = None
    req_payload = None
    rsq_payload = None

    # def validate_ip(ip):
    #     if re.match(r"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$",ip) != None:
    #         return True
    #     else:
    #         print("The ip address you provides is invalid %s exiting" % (ip))
    #         sys.exit(-1)


    # (options, args) = parser.parse_args()
    # if options == []:
    #    print(parser.print_help())
    # #    sys.exit(-1)
    # if not options.output_pcap or options.output_pcap == "":
    #    print(parser.print_help())
    # #    sys.exit(-1)
    # if options.srcip and validate_ip(options.srcip):
    #    src = options.srcip 
    # if options.dstip and validate_ip(options.dstip):
    #    dst = options.dstip
    # if not options.req_payload or options.req_payload == "":
    #    print(parser.print_help())
    # #    sys.exit(-1)
    # if not options.rsq_payload or options.rsq_payload == "":
    #    print(parser.print_help())
    # #    sys.exit(-1)

    def __init__(self,output_pcap) -> None:
        self.output_pcap = output_pcap
        #Open our packet dumper
        self.pktdump = PcapWriter(self.output_pcap, sync=True)

        pass

    def build_handshake(self,mac_src,mac_dst,src,dst,sport,dport):
        macsrc  = mac_src
        macdst  = mac_dst
        ipsrc   = src
        ipdst   = dst
        portsrc = sport
        portdst = dport

    #    We don't deal with session wrap around so lets make the range smaller for now
    #    client_isn = random.randint(1024, (2**32)-1)
    #    server_isn = random.randint(1024, (2**32)-1)
        client_isn = random.randint(1024, 10000)
        server_isn = random.randint(1024, 10000)
        syn = Ether(src=macsrc,dst=macdst)/IP(src=ipsrc, dst=ipdst)/TCP(flags="S", sport=portsrc, dport=portdst, seq=client_isn)
        synack = Ether(src=macsrc,dst=macdst)/IP(src=ipdst, dst=ipsrc)/TCP(flags="SA", sport=portdst, dport=portsrc, seq=server_isn, ack=syn.seq+1)
        ack = Ether(src=macsrc,dst=macdst)/IP(src=ipsrc, dst=ipdst)/TCP(flags="A", sport=portsrc, dport=portdst, seq=syn.seq+1, ack=synack.seq+1)
        self.pktdump.write(syn)
        self.pktdump.write(synack)
        self.pktdump.write(ack)
        return(ack.seq,ack.ack)

    def build_finshake(self,mac_src,mac_dst,src,dst,sport,dport,seq,ack):
        macsrc  = mac_src
        macdst  = mac_dst
        ipsrc   = src
        ipdst   = dst
        portsrc = sport
        portdst = dport
        finAck = Ether(src=macsrc,dst=macdst)/IP(src=ipsrc, dst=ipdst)/TCP(flags="FA", sport=sport, dport=dport, seq=seq, ack=ack)
        finalAck = Ether(src=macsrc,dst=macdst)/IP(src=ipdst, dst=ipsrc)/TCP(flags="A", sport=dport, dport=sport, seq=finAck.ack, ack=finAck.seq+1)
        self.pktdump.write(finAck)
        self.pktdump.write(finalAck)

    #http://stackoverflow.com/questions/18854620/whats-the-best-way-to-split-a-string-into-fixed-length-chunks-and-work-with-the
    def chunkstring(self,string, length):
        return (string[0+i:length+i] for i in range(0, len(string), length))

    def make_poop(self,mac_src,mac_dst,src,dst,sport,dport,seq,ack,payload):
        segments = [] 
        if len(payload) > 1460:
            segments=chunkstring(payload,1460)
        else:
            segments.append(payload)   
            
        macsrc  = mac_src
        macdst  = mac_dst 
        ipsrc   = src
        ipdst   = dst
        portsrc = sport
        portdst = dport
        for segment in segments:
            p = Ether(src=macsrc,dst=macdst)/IP(src=ipsrc, dst=ipdst)/TCP(flags="PA", sport=sport, dport=dport, seq=seq, ack=ack)/segment
            returnAck = Ether(src=macsrc,dst=macdst)/IP(src=ipdst, dst=ipsrc)/TCP(flags="A", sport=dport, dport=sport, seq=p.ack, ack=(p.seq + len(p[Raw])))
            seq = returnAck.ack
            ack = returnAck.seq
            self.pktdump.write(p)
            self.pktdump.write(returnAck)
        return(returnAck.seq,returnAck.ack)

    def close(self):
        self.pktdump.close()
        
    def build(self,src, dst, sport, dport, req_payload, rsq_payload):
        macsrc  = "00:0c:29:65:b0:ba"
        macdst  = "00:50:56:c0:00:01"
        (seq,ack)=self.build_handshake(macsrc,macdst,src,dst,sport,dport)
        (seq,ack)=self.make_poop(macsrc,macdst,src,dst,sport,dport,seq,ack,req_payload)
        (seq,ack)=self.make_poop(macsrc,macdst,dst,src,dport,sport,seq,ack,rsq_payload)
        self.build_finshake(macsrc,macdst,src,dst,sport,dport,seq,ack)


if __name__ == "__main__":
    obj = BUILD2PCAP("test.pcap")
    src = "192.168.92.1"
    dst = "192.168.92.133"
    sport = 63782
    dport = 80
    
    urls = [
        "/proxy-jl/bmFjb3NjYWNvc25hY29zbmFjb25hY29zbmFjb3NuYWNvc25hY29zbmFjb3NuYWNvcw/v1/console/namespaces",
        "/proxy-jl/bmFjb3NjYWNvc25hY29zbmFjb25hY29zbmFjb3NuYWNvc25hY29zbmFjb3NuYWNvcw/v1/console/server/state"
    ]
    
    for index,url in enumerate(urls):
        sport = index % 65535 + 1
    
        req_payload = f"GET {url} HTTP/1.1\r\n"
        req_payload += "Host: ci.qianxin-inc.cn\r\n"
        req_payload += "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0\r\n"
        req_payload += "Accept-Encoding: gzip, deflate\r\n"
        req_payload += "Accept: */*\r\n"
        req_payload += "Connection: close\r\n"
        req_payload += "\r\n"


        rsq_payload  = "HTTP/1.1 200 OK\r\n"
        rsq_payload += "Date: Sat, 21 May 2022 16:09:24 GMT\r\n"
        rsq_payload += "Content-Type: application/json\r\n"
        rsq_payload += "Content-Length: 42\r\n"
        rsq_payload += "Connection: close\r\n"
        rsq_payload += "\r\n"
        rsq_payload += '{"status":"success","result":"nginx json"}'

        print("src: %s dst: %s sport: %s dport: %s req_payload: %s rsq_payload: %s" % (src, dst, sport, dport, req_payload, rsq_payload))
        obj.build(src, dst, sport, dport, req_payload, rsq_payload)
        
    obj.close()





